package com.mikufufu.blog.controller.system;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mikufufu.blog.common.annotation.Anonymous;
import com.mikufufu.blog.common.annotation.OperationLog;
import com.mikufufu.blog.common.cache.RedisCache;
import com.mikufufu.blog.common.constant.RedisKey;
import com.mikufufu.blog.common.entity.AjaxResult;
import com.mikufufu.blog.common.enums.HtmlTemplate;
import com.mikufufu.blog.common.enums.ModuleType;
import com.mikufufu.blog.common.enums.OperationType;
import com.mikufufu.blog.model.dto.ForgetPasswordParam;
import com.mikufufu.blog.model.dto.LoginEmailParam;
import com.mikufufu.blog.model.dto.LoginParam;
import com.mikufufu.blog.model.dto.api.RegisterParam;
import com.mikufufu.blog.model.entity.User;
import com.mikufufu.blog.security.enums.Channel;
import com.mikufufu.blog.security.enums.UserStatus;
import com.mikufufu.blog.service.EmailService;
import com.mikufufu.blog.service.UserService;
import com.mikufufu.blog.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.Email;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Validated // 开启参数校验,只有在类上添加@Validated注解时，Get才会开启参数校验
@RestController
@Api(tags = "登录模块")
public class LoginController {

    @Autowired
    private UserService userService;

    @Autowired
    private EmailService emailService;


    @PostMapping("/register")
    @ApiOperation(value = "注册新用户")
    public AjaxResult<String> register(@RequestBody @Validated RegisterParam user) {
        return AjaxResult.data(userService.register(user));
    }

    @PostMapping("/login")
    @ApiOperation(value = "c端登录")
    public AjaxResult<String> login(@RequestBody @Validated LoginParam loginParam) {
        return AjaxResult.data(userService.login(loginParam, Channel.WEB));
    }

    @PostMapping("/admin/login")
    @ApiOperation(value = "管理端登录")
    @OperationLog(module = ModuleType.USER,type = OperationType.LOGIN, description = "管理端登录")
    public AjaxResult<String> adminLogin(@RequestBody @Validated LoginParam loginParam) {
        return AjaxResult.data(userService.login(loginParam,Channel.ADMIN));
    }

    @PostMapping("/loginByEmail")
    @ApiOperation(value = "c端登录")
    public AjaxResult<String> loginByEmail(@RequestBody @Validated LoginEmailParam loginEmailParam) {
        return AjaxResult.data(userService.loginEmail(loginEmailParam,Channel.WEB));
    }

    @PostMapping("/admin/loginByEmail")
    @ApiOperation(value = "管理端登录")
    @OperationLog(module = ModuleType.USER,type = OperationType.LOGIN, description = "管理端登录")
    public AjaxResult<String> adminLoginByEmail(@RequestBody @Validated LoginEmailParam loginEmailParam) {
        return AjaxResult.data(userService.loginEmail(loginEmailParam,Channel.ADMIN));
    }

    @GetMapping("/logout")
    @ApiOperation(value = "登出")
    public AjaxResult<Boolean> logout() {
        return AjaxResult.status(userService.logout());
    }

    @Anonymous
    @GetMapping("/sendMailCode")
    @ApiOperation(value = "发送邮箱验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "email", value = "邮箱地址", required = true),
            @ApiImplicitParam(name = "type", value = "1:注册 2:忘记密码", required = true)
    })
    @OperationLog(module = ModuleType.USER,type = OperationType.SEND_EMAIL, description = "发送邮箱验证码")
    public AjaxResult<Void> sendMailCode(@RequestParam @Email(message = "请输入正确的邮箱地址") String email, Integer type) {

        // 判断是否发送过验证码
        if (RedisCache.exists(RedisKey.EMAIL_CODE_EXPIRATION_TIME + email)){
            return AjaxResult.error("请勿频繁发送验证码");
        }else if (RedisCache.exists(RedisKey.EMAIL_CODE + email)) {
            RedisCache.delete(RedisKey.EMAIL_CODE + email);
        }

        if(type != null && type == 2 && !userService.exists(new LambdaQueryWrapper<User>().select(User::getId).eq(User::getEmail, email).eq(User::getStatus, UserStatus.NORMAL))){
            return AjaxResult.error("该邮箱未注册");
        }
        // 生成验证码
        String code = StringUtils.threadLocalRandom();

        // 保存验证码到redis中
        RedisCache.set(RedisKey.EMAIL_CODE + email, code, 6, TimeUnit.MINUTES);
        RedisCache.set(RedisKey.EMAIL_CODE_EXPIRATION_TIME + email, 1, 1, TimeUnit.MINUTES);

        // 构造邮件内容
        Map<String, String> values = new HashMap<>();
        values.put("code", code);
        values.put("expire", "6");
        values.put("time", LocalDateTime.now().plusMinutes(6).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        emailService.sendTemplateEmail("小缡", email, HtmlTemplate.EMAIL_CODE, values);

        return AjaxResult.success();
    }

    @Anonymous
    @PostMapping("/forgetPassword")
    @ApiOperation(value = "忘记密码")
    public AjaxResult<Boolean> forgetPassword(@RequestBody @Validated ForgetPasswordParam forgetPasswordParam) {
        return AjaxResult.status(userService.forgetPassword(forgetPasswordParam));
    }
}
